home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / xshp15.zip / FIXED.ASM < prev    next >
Assembly Source File  |  1992-01-10  |  13KB  |  388 lines

  1. ; 386-specific fixed point routines.
  2. ; Tested with TASM 3.0.
  3. ROUNDING_ON    equ    1    ;1 for rounding, 0 for no rounding
  4.                 ;no rounding is faster, rounding is
  5.                 ; more accurate
  6. ALIGNMENT    equ    2
  7.     .model small
  8.     .386
  9.     .code
  10. ;=====================================================================
  11. ; Multiplies two fixed-point values together.
  12. ; C near-callable as:
  13. ;    Fixedpoint FixedMul(Fixedpoint M1, Fixedpoint M2);
  14. ;    Fixedpoint FixedDiv(Fixedpoint Dividend, Fixedpoint Divisor);
  15. FMparms struc
  16.     dw    2 dup(?)    ;return address & pushed BP
  17. M1    dd    ?
  18. M2    dd    ?
  19. FMparms ends
  20.     align    ALIGNMENT
  21.     public    _FixedMul
  22. _FixedMul       proc    near
  23.         push    bp
  24.         mov     bp,sp
  25.         mov     eax,[bp+M1]
  26.         imul    dword ptr [bp+M2] ;multiply
  27. if ROUNDING_ON
  28.         add     eax,8000h       ;round by adding 2^(-17)
  29.         adc     edx,0           ;whole part of result is in DX
  30. endif ;ROUNDING_ON
  31.         shr     eax,16          ;put the fractional part in AX
  32.         pop     bp
  33.         ret
  34. _FixedMul       endp
  35. ;=====================================================================
  36. ; Divides one fixed-point value by another.
  37. ; C near-callable as:
  38. ;    Fixedpoint FixedDiv(Fixedpoint Dividend, Fixedpoint Divisor);
  39. FDparms struc
  40.     dw    2 dup(?)    ;return address & pushed BP
  41. Dividend dd    ?
  42. Divisor  dd    ?
  43. FDparms ends
  44.     align    ALIGNMENT
  45.     public    _FixedDiv
  46. _FixedDiv       proc    near
  47.         push    bp
  48.         mov     bp,sp
  49.  
  50. if ROUNDING_ON
  51.         sub     cx,cx           ;assume positive result
  52.         mov     eax,[bp+Dividend]
  53.         and     eax,eax         ;positive dividend?
  54.         jns     FDP1            ;yes
  55.         inc     cx              ;mark it's a negative dividend
  56.         neg     eax             ;make the dividend positive
  57. FDP1:   sub     edx,edx         ;make it a 64-bit dividend, then shift
  58.                                 ; left 16 bits so that result will be
  59.                                 ; in EAX
  60.         rol     eax,16          ;put fractional part of dividend in
  61.                                 ; high word of EAX
  62.         mov     dx,ax           ;put whole part of dividend in DX
  63.         sub     ax,ax           ;clear low word of EAX
  64.         mov     ebx,dword ptr [bp+Divisor]
  65.         and     ebx,ebx         ;positive divisor?
  66.         jns     FDP2            ;yes
  67.         dec     cx              ;mark it's a negative divisor
  68.         neg     ebx             ;make divisor positive
  69. FDP2:   div     ebx             ;divide
  70.         shr     ebx,1           ;divisor/2, minus 1 if the divisor is
  71.         adc     ebx,0           ; even
  72.         dec     ebx
  73.         cmp     ebx,edx         ;set Carry if remainder is at least
  74.         adc     eax,0           ; half as large as the divisor, then
  75.                                 ; use that to round up if necessary
  76.         and     cx,cx           ;should the result be made negative?
  77.         jz      FDP3            ;no
  78.         neg     eax             ;yes, negate it
  79. FDP3:
  80. else ;!ROUNDING_ON
  81.     mov    edx,[bp+Dividend]
  82.     sub    eax,eax
  83.     shrd    eax,edx,16    ;position so that result ends up
  84.     sar    edx,16        ; in EAX
  85.     idiv    dword ptr [bp+Divisor]
  86. endif ;ROUNDING_ON
  87.     shld    edx,eax,16    ;whole part of result in DX;
  88.                        ; fractional part is already in AX
  89.         pop     bp
  90.         ret
  91. _FixedDiv       endp
  92. ;=====================================================================
  93. ; Returns the sine and cosine of an angle.
  94. ; C near-callable as:
  95. ;    void CosSin(TAngle Angle, Fixedpoint *Cos, Fixedpoint *);
  96.  
  97.     align    ALIGNMENT
  98. CosTable label dword
  99.     include costable.inc
  100.  
  101. SCparms struc
  102.     dw    2 dup(?)    ;return address & pushed BP
  103. Angle    dw    ?        ;angle to calculate sine & cosine for
  104. Cos    dw    ?        ;pointer to cos destination
  105. Sin    dw    ?        ;pointer to sin destination
  106. SCparms ends
  107.  
  108.     align    ALIGNMENT
  109.     public _CosSin
  110. _CosSin    proc    near
  111.     push    bp        ;preserve stack frame
  112.     mov    bp,sp        ;set up local stack frame
  113.  
  114.     mov    bx,[bp].Angle
  115.     and    bx,bx        ;make sure angle's between 0 and 2*pi
  116.     jns    CheckInRange
  117. MakePos:            ;less than 0, so make it positive
  118.     add    bx,360*10
  119.     js    MakePos
  120.     jmp    short CheckInRange
  121.  
  122.     align    ALIGNMENT
  123. MakeInRange:            ;make sure angle is no more than 2*pi
  124.     sub       bx,360*10
  125. CheckInRange:
  126.     cmp       bx,360*10
  127.     jg        MakeInRange
  128.  
  129.     cmp    bx,180*10    ;figure out which quadrant
  130.     ja    BottomHalf    ;quadrant 2 or 3
  131.     cmp    bx,90*10    ;quadrant 0 or 1
  132.     ja    Quadrant1
  133.                 ;quadrant 0
  134.     shl       bx,2
  135.     mov    eax,CosTable[bx] ;look up sine
  136.     neg    bx        ;sin(Angle) = cos(90-Angle)
  137.     mov    edx,CosTable[bx+90*10*4] ;look up cosine
  138.     jmp    short CSDone
  139.  
  140.     align    ALIGNMENT
  141. Quadrant1:
  142.     neg    bx
  143.     add    bx,180*10    ;convert to angle between 0 and 90
  144.     shl       bx,2
  145.     mov    eax,CosTable[bx] ;look up cosine
  146.     neg    eax        ;negative in this quadrant
  147.     neg    bx        ;sin(Angle) = cos(90-Angle)
  148.     mov    edx,CosTable[bx+90*10*4] ;look up cosine
  149.     jmp    short CSDone
  150.  
  151.     align    ALIGNMENT
  152. BottomHalf:            ;quadrant 2 or 3
  153.     neg    bx
  154.     add    bx,360*10    ;convert to angle between 0 and 180
  155.     cmp    bx,90*10    ;quadrant 2 or 3
  156.     ja    Quadrant2
  157.                 ;quadrant 3
  158.     shl       bx,2
  159.     mov    eax,CosTable[bx] ;look up cosine
  160.     neg    bx        ;sin(Angle) = cos(90-Angle)
  161.     mov    edx,CosTable[90*10*4+bx] ;look up sine
  162.     neg    edx        ;negative in this quadrant
  163.     jmp    short CSDone
  164.  
  165.     align    ALIGNMENT
  166. Quadrant2:
  167.     neg    bx
  168.     add    bx,180*10    ;convert to angle between 0 and 90
  169.     shl       bx,2
  170.     mov    eax,CosTable[bx] ;look up cosine
  171.     neg    eax        ;negative in this quadrant
  172.     neg    bx        ;sin(Angle) = cos(90-Angle)
  173.     mov    edx,CosTable[90*10*4+bx] ;look up sine
  174.     neg    edx        ;negative in this quadrant
  175. CSDone:
  176.     mov    bx,[bp].Cos
  177.     mov    [bx],eax
  178.     mov    bx,[bp].Sin
  179.     mov    [bx],edx
  180.  
  181.     pop    bp        ;restore stack frame
  182.     ret
  183. _CosSin    endp
  184. ;=====================================================================
  185. ; Matrix multiplies Xform by SourceVec, and stores the result in
  186. ; DestVec. Multiplies a 4x4 matrix times a 4x1 matrix; the result
  187. ; is a 4x1 matrix. Cheats by assuming the W coord is 1 and the
  188. ; bottom row of the matrix is 0 0 0 1, and doesn't bother to set
  189. ; the W coordinate of the destination.
  190. ; C near-callable as:
  191. ;    void XformVec(Xform WorkingXform, Fixedpoint *SourceVec,
  192. ;        Fixedpoint *DestVec);
  193. ;
  194. ; This assembly code is equivalent to this C code:
  195. ;   int i;
  196. ;
  197. ;   for (i=0; i<3; i++)
  198. ;      DestVec[i] = FixedMul(WorkingXform[i][0], SourceVec[0]) +
  199. ;         FixedMul(WorkingXform[i][1], SourceVec[1]) +
  200. ;         FixedMul(WorkingXform[i][2], SourceVec[2]) +
  201. ;         WorkingXform[i][3];   /* no need to multiply by W = 1 */
  202.  
  203. XVparms struc
  204.     dw    2 dup(?)    ;return address & pushed BP
  205. WorkingXform dw    ?        ;pointer to transform matrix
  206. SourceVec dw    ?        ;pointer to source vector
  207. DestVec    dw    ?        ;pointer to destination vector
  208. XVparms ends
  209.  
  210.     align    ALIGNMENT
  211.     public _XformVec
  212. _XformVec    proc    near
  213.     push    bp        ;preserve stack frame
  214.     mov    bp,sp        ;set up local stack frame
  215.     push    si        ;preserve register variables
  216.     push    di
  217.  
  218.     mov       si,[bp].WorkingXform ;SI points to xform matrix
  219.     mov       bx,[bp].SourceVec    ;BX points to source vector
  220.     mov       di,[bp].DestVec      ;DI points to dest vector
  221.  
  222. soff=0
  223. doff=0
  224.     REPT 3               ;do once each for dest X, Y, and Z
  225.     mov       eax,[si+soff]      ;column 0 entry on this row
  226.     imul      dword ptr [bx]     ;xform entry times source X entry
  227. if ROUNDING_ON
  228.         add     eax,8000h       ;round by adding 2^(-17)
  229.         adc     edx,0           ;whole part of result is in DX
  230. endif ;ROUNDING_ON
  231.     shrd    eax,edx,16    ;shift the result back to 16.16 form
  232.     mov       ecx,eax            ;set running total
  233.  
  234.     mov       eax,[si+soff+4]    ;column 1 entry on this row
  235.     imul      dword ptr [bx+4] ;xform entry times source Y entry
  236. if ROUNDING_ON
  237.         add     eax,8000h       ;round by adding 2^(-17)
  238.         adc     edx,0           ;whole part of result is in DX
  239. endif ;ROUNDING_ON
  240.     shrd    eax,edx,16      ;shift the result back to 16.16 form
  241.     add       ecx,eax            ;running total for this row
  242.  
  243.     mov       eax,[si+soff+8]    ;column 2 entry on this row
  244.     imul      dword ptr [bx+8] ;xform entry times source Z entry
  245. if ROUNDING_ON
  246.         add     eax,8000h       ;round by adding 2^(-17)
  247.         adc     edx,0           ;whole part of result is in DX
  248. endif ;ROUNDING_ON
  249.     shrd    eax,edx,16    ;shift the result back to 16.16 form
  250.     add       ecx,eax            ;running total for this row
  251.  
  252.     add       ecx,[si+soff+12] ;add in translation
  253.     mov       [di+doff],ecx      ;save the result in the dest vector
  254. soff=soff+16
  255. doff=doff+4
  256.     ENDM
  257.  
  258.     pop    di        ;restore register variables
  259.     pop    si
  260.     pop    bp        ;restore stack frame
  261.     ret
  262. _XformVec    endp
  263. ;=====================================================================
  264. ; Matrix multiplies SourceXform1 by SourceXform2 and stores the
  265. ; result in DestXform. Multiplies a 4x4 matrix times a 4x4 matrix;
  266. ; the result is a 4x4 matrix. Cheats by assuming the bottom row of
  267. ; each matrix is 0 0 0 1, and doesn't bother to set the bottom row
  268. ; of the destination.
  269. ; C near-callable as:
  270. ;       void ConcatXforms(Xform SourceXform1, Xform SourceXform2,
  271. ;               Xform DestXform)
  272. ;
  273. ; This assembly code is equivalent to this C code:
  274. ;   int i, j;
  275. ;
  276. ;   for (i=0; i<3; i++) {
  277. ;      for (j=0; j<3; j++)
  278. ;         DestXform[i][j] =
  279. ;               FixedMul(SourceXform1[i][0], SourceXform2[0][j]) +
  280. ;               FixedMul(SourceXform1[i][1], SourceXform2[1][j]) +
  281. ;               FixedMul(SourceXform1[i][2], SourceXform2[2][j]);
  282. ;      DestXform[i][3] =
  283. ;            FixedMul(SourceXform1[i][0], SourceXform2[0][3]) +
  284. ;            FixedMul(SourceXform1[i][1], SourceXform2[1][3]) +
  285. ;            FixedMul(SourceXform1[i][2], SourceXform2[2][3]) +
  286. ;            SourceXform1[i][3];
  287. ;   }
  288.  
  289. CXparms struc
  290.     dw    2 dup(?)    ;return address & pushed BP
  291. SourceXform1 dw ?               ;pointer to first source xform matrix
  292. SourceXform2 dw ?               ;pointer to second source xform matrix
  293. DestXform    dw ?               ;pointer to destination xform matrix
  294. CXparms ends
  295.  
  296.     align    ALIGNMENT
  297.     public _ConcatXforms
  298. _ConcatXforms    proc    near
  299.     push    bp        ;preserve stack frame
  300.     mov    bp,sp        ;set up local stack frame
  301.     push    si        ;preserve register variables
  302.     push    di
  303.  
  304.     mov     bx,[bp].SourceXform2 ;BX points to xform2 matrix
  305.     mov     si,[bp].SourceXform1 ;SI points to xform1 matrix
  306.     mov     di,[bp].DestXform    ;DI points to dest xform matrix
  307.  
  308. roff=0                          ;row offset
  309.     REPT 3                  ;once for each row
  310. coff=0                          ;column offset
  311.     REPT 3                  ;once for each of the first 3 columns,
  312.                 ; assuming 0 as the bottom entry (no
  313.                 ; translation)
  314.     mov     eax,[si+roff]   ;column 0 entry on this row
  315.     imul    dword ptr [bx+coff] ;times row 0 entry in column
  316. if ROUNDING_ON
  317.         add     eax,8000h       ;round by adding 2^(-17)
  318.         adc     edx,0           ;whole part of result is in DX
  319. endif ;ROUNDING_ON
  320.     shrd    eax,edx,16    ;shift the result back to 16.16 form
  321.     mov     ecx,eax         ;set running total
  322.  
  323.     mov     eax,[si+roff+4] ;column 1 entry on this row
  324.     imul    dword ptr [bx+coff+16] ;times row 1 entry in col
  325. if ROUNDING_ON
  326.         add     eax,8000h       ;round by adding 2^(-17)
  327.         adc     edx,0           ;whole part of result is in DX
  328. endif ;ROUNDING_ON
  329.     shrd    eax,edx,16      ;shift the result back to 16.16 form
  330.     add     ecx,eax         ;running total
  331.  
  332.     mov     eax,[si+roff+8] ;column 2 entry on this row
  333.     imul    dword ptr [bx+coff+32] ;times row 2 entry in col
  334. if ROUNDING_ON
  335.         add     eax,8000h       ;round by adding 2^(-17)
  336.         adc     edx,0           ;whole part of result is in DX
  337. endif ;ROUNDING_ON
  338.     shrd    eax,edx,16    ;shift the result back to 16.16 form
  339.     add     ecx,eax         ;running total
  340.  
  341.     mov     [di+coff+roff],ecx ;save the result in dest matrix
  342. coff=coff+4                    ;point to next col in xform2 & dest
  343.     ENDM
  344.                 ;now do the fourth column, assuming
  345.                 ; 1 as the bottom entry, causing
  346.                 ; translation to be performed
  347.     mov     eax,[si+roff]   ;column 0 entry on this row
  348.     imul    dword ptr [bx+coff] ;times row 0 entry in column
  349. if ROUNDING_ON
  350.         add     eax,8000h       ;round by adding 2^(-17)
  351.         adc     edx,0           ;whole part of result is in DX
  352. endif ;ROUNDING_ON
  353.     shrd    eax,edx,16    ;shift the result back to 16.16 form
  354.     mov     ecx,eax         ;set running total
  355.  
  356.     mov     eax,[si+roff+4] ;column 1 entry on this row
  357.     imul    dword ptr [bx+coff+16] ;times row 1 entry in col
  358. if ROUNDING_ON
  359.         add     eax,8000h       ;round by adding 2^(-17)
  360.         adc     edx,0           ;whole part of result is in DX
  361. endif ;ROUNDING_ON
  362.     shrd    eax,edx,16      ;shift the result back to 16.16 form
  363.     add     ecx,eax         ;running total
  364.  
  365.     mov     eax,[si+roff+8] ;column 2 entry on this row
  366.     imul    dword ptr [bx+coff+32] ;times row 2 entry in col
  367. if ROUNDING_ON
  368.         add     eax,8000h       ;round by adding 2^(-17)
  369.         adc     edx,0           ;whole part of result is in DX
  370. endif ;ROUNDING_ON
  371.     shrd    eax,edx,16    ;shift the result back to 16.16 form
  372.     add     ecx,eax         ;running total
  373.  
  374.     add     ecx,[si+roff+12] ;add in translation
  375.  
  376.     mov     [di+coff+roff],ecx ;save the result in dest matrix
  377. coff=coff+4                    ;point to next col in xform2 & dest
  378.  
  379. roff=roff+16                    ;point to next col in xform2 & dest
  380.     ENDM
  381.  
  382.     pop    di        ;restore register variables
  383.     pop    si
  384.     pop    bp        ;restore stack frame
  385.     ret
  386. _ConcatXforms    endp
  387.     end
  388.